home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Online / NNTPd / server / serve.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-12-03  |  10.5 KB  |  535 lines

  1. #ifndef lint
  2. static char    sccsid[] = "@(#)$Id: serve.c,v 1.41 1994/12/03 21:54:30 sob Exp sob $";
  3. #endif
  4.  
  5. /*
  6.  * Main server routine
  7.  */
  8.  
  9. #include "common.h"
  10. #include <signal.h>
  11. #ifdef USG
  12. #include <sys/times.h>
  13. #else
  14. #include <sys/time.h>
  15. #endif
  16.  
  17. #ifdef LOG
  18. # ifndef USG
  19. #  include <sys/resource.h>
  20. # endif
  21. #endif
  22.  
  23. #ifdef TIMERS
  24. #include "timer.h"
  25. #endif
  26.  
  27. extern    void    ahbs(), dodate(), group(), help(), ihave();
  28. extern    void    list(), newgroups(), newnews(), nextlast(), post();
  29. extern    void    slave(), xlistgroup(), xhdr(), doxover(), xthread(), xindex();
  30. extern    void    xgtitle(), doxrover(), doxmode();
  31.  
  32. extern int errno;
  33.  
  34. #ifdef AUTH
  35. extern    void    doxauthcap(), doxauthinfo(), doxauthsys();
  36. #endif
  37.  
  38. #ifdef GENAUTH
  39. #define    A 1
  40. #else
  41. #define    A 0
  42. #endif
  43.  
  44. static struct cmdent {
  45.     char    *cmd_name;
  46.     int    authreq;    /* 0=none,1=userpass */
  47.     void    (*cmd_fctn)();
  48. } cmdtbl[] = {
  49. #ifdef AUTH
  50.     "authcap",    0,    doxauthcap,
  51.     "authinfo",    0,    doxauthinfo,
  52.     "authsys",    0,    doxauthsys,
  53. #endif
  54.     "article",    A,    ahbs,
  55.     "body",        A,    ahbs,
  56.     "date",        0,    dodate,
  57.     "group",    A,    group,
  58.     "head",        A,    ahbs,
  59.     "help",        0,    help,
  60.     "ihave",    1,    ihave,
  61.     "last",        A,    nextlast,
  62.     "list",        A,    list,
  63. #ifdef LISTGROUP
  64.     "listgroup",    A,    xlistgroup,
  65. #endif
  66.     "mode",        0,    doxmode,
  67.     "newgroups",    A,    newgroups,
  68.     "newnews",    A,    newnews,
  69.     "next",        A,    nextlast,
  70.     "post",        1,    post,
  71.     "slave",    0,    slave,
  72.     "stat",        A,    ahbs,
  73.     "xgtitle",    A,    xgtitle,
  74. #ifdef XHDR
  75.     "xhdr",        A,    xhdr,
  76. #endif
  77. #ifdef XINDEX
  78.     "xindex",    A,    xindex,
  79. #endif
  80. #ifdef XOVER
  81.     "xover",    A,    doxover,
  82. #endif
  83. #ifdef XTHREAD
  84.     "xthread",    A,    xthread,
  85. #endif
  86. #ifdef XROVER
  87.     "xrover",    A,    doxrover,
  88. #endif
  89. };
  90. #define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent))
  91.  
  92. #ifdef TIMEOUT
  93. static void timeout();
  94. #endif
  95. #ifdef LOGINCHECK
  96. static void logincheck();
  97. static int firstlogincheck;
  98. #endif
  99. #ifdef BATCHED_INPUT
  100. static void batchcheck();
  101. #endif
  102.  
  103. #ifdef TIMERS
  104. static struct timer timers[] = {
  105. #ifdef TIMEOUT
  106.     { timeout, 1, TIMEOUT, 0 },
  107. #endif
  108. #ifdef LOGINCHECK
  109.     { logincheck, 0, LOGINCHECK, 0 },
  110. #endif
  111. #ifdef BATCHCHECK
  112.     { batchcheck, 1, BATCHCHECK, 0 },
  113. #endif
  114. };
  115. #define NTIMERS (sizeof(timers) / sizeof(struct timer))
  116. #endif
  117.  
  118. static char *stats_init();
  119. #ifdef LOG
  120. static void stats_finish();
  121. #endif
  122.  
  123. #ifdef AUTH
  124. extern int    Needauth;
  125. extern char    User[];
  126. #endif
  127.  
  128. /*
  129.  * serve -- given a connection on stdin/stdout, serve
  130.  *    a client, executing commands until the client
  131.  *    says goodbye.
  132.  *
  133.  *    Parameters:    None.
  134.  *
  135.  *    Returns:    Exits.
  136.  *
  137.  *    Side effects:    Talks to client, does a lot of
  138.  *            stuff.
  139.  */
  140.  
  141. void
  142. serve()
  143. {
  144.     char        line[NNTP_STRLEN];
  145.     char        host[MAXHOSTNAMELEN];
  146.     char        gdbuf[MAXBUFLEN];
  147.     char        **argp;
  148.     char        *timeptr, *cp;
  149.     int        argnum, i;
  150. #ifdef POSTER
  151.     struct passwd    *pp;
  152. #endif
  153. #ifdef LOG
  154.     grps_acsd = arts_acsd = 0;
  155. #endif
  156.  
  157.     /* Not all systems pass fd's 1 and 2 from inetd */
  158.  
  159.     (void) close(1);
  160.     (void) close(2);
  161.     (void) dup(0);
  162.     (void) dup(0);
  163.  
  164.     /* If we're ALONE, then we've already opened syslog */
  165.  
  166. #ifndef ALONE
  167. # ifdef SYSLOG
  168. #  ifdef LOG_DAEMON
  169.     openlog("nntpd", LOG_PID, SYSLOG);
  170. #  else
  171.     openlog("nntpd", LOG_PID);
  172. #  endif
  173. # endif
  174. #endif
  175.  
  176.     timeptr = stats_init();
  177.  
  178. #ifdef ALONE
  179. #ifndef USG
  180.     (void) signal(SIGCHLD, SIG_IGN);
  181. #endif
  182. #endif
  183.  
  184.     /* Ignore SIGPIPE, since we'll see closed connections with read */
  185.  
  186.     (void) signal(SIGPIPE, SIG_IGN);
  187.  
  188.     /* Get permissions and see if we can talk to this client */
  189. #ifdef AUTH
  190.     Needauth = 1;
  191.     strcpy(User,"");
  192. #endif
  193.     host_access(&canread, &canpost, &canxfer, gdbuf);
  194.  
  195.     if (gethostname(host, sizeof(host)) < 0)
  196.         (void) strcpy(host, "Amnesiac");
  197.  
  198. #ifdef SETPROCTITLE
  199.     setproctitle("%s", hostname);
  200. #endif
  201.  
  202.     if (!canread && !canxfer) {
  203.         printf("%d %s NNTP server can't talk to you.  Goodbye.\r\n",
  204.             ERR_ACCESS, host);
  205.         (void) fflush(stdout);
  206.         (void) fclose(stdout);
  207. #ifdef SYSLOG
  208.         syslog(LOG_INFO, "%s refused connection", hostname);
  209. #endif
  210.         exit(1);
  211.     }
  212.  
  213. #ifdef LOGINCHECK
  214.     firstlogincheck = 1;
  215.     logincheck();
  216.     firstlogincheck = 0;
  217. #endif
  218.  
  219.     if ( !canpost && !canread && !space(MINFREE)) {
  220.         printf("%d %s NNTP server out of space. Try later.\r\n",
  221.             ERR_GOODBYE, host);
  222.         (void) fflush(stdout);
  223. #ifdef SYSLOG
  224.         syslog(LOG_INFO, "%s no space", hostname);
  225. #endif
  226.         exit(1);
  227.     }
  228.  
  229.     /* If we can talk, proceed with initialization */
  230.  
  231.     ngpermcount = get_nglist(&ngpermlist, gdbuf);
  232.  
  233. #ifdef POSTER
  234.     pp = getpwnam(POSTER);
  235.     if (pp != NULL) {
  236.         uid_poster = pp->pw_uid;
  237.         gid_poster = pp->pw_gid;
  238.         home_poster = pp->pw_dir;
  239.     } else
  240. #endif
  241.     {
  242.         uid_poster = gid_poster = 0;
  243.         home_poster = "/";
  244.     }
  245.  
  246. #ifndef FASTFORK
  247.     num_groups = 0;
  248.     num_groups = read_groups();    /* Read in the active file */
  249. #else
  250.     signal(SIGALRM, SIG_IGN);    /* Children don't deal with */
  251.                     /* these things */
  252. #endif
  253.     /*
  254.      * num_groups may be zero if expire is running and the active
  255.      * file is locked. (Under System V with lockf, for example.)
  256.      * Or, something may be really screwed up....
  257.      */
  258.     if (num_groups == 0){ /* can't get a group list */
  259.         printf("%d %s NNTP server unavailable. Try later.\r\n",
  260.             ERR_FAULT, host);
  261.         (void) fflush(stdout);
  262. #ifdef SYSLOG
  263.         syslog(LOG_INFO, "%s no groups", hostname);
  264. #endif
  265.         exit(1);
  266.     }
  267.  
  268.     art_fp = NULL;
  269.     argp = (char **) NULL;        /* for first time */
  270.  
  271.     if ((cp = index(timeptr, '\n')) != NULL)
  272.         *cp = '\0';
  273.     else
  274.         timeptr = "Unknown date";
  275. #ifdef AUTH
  276.     printf("%d %s NNTP[auth] server version %s ready at %s (%s).\r\n",
  277. #else
  278.     printf("%d %s NNTP server version %s ready at %s (%s).\r\n",
  279. #endif
  280.         canpost ? OK_CANPOST : OK_NOPOST,
  281.         host, nntp_version,
  282.         timeptr,
  283.         canpost ? "posting ok" : "no posting");
  284.     (void) fflush(stdout);
  285.  
  286.     /*
  287.      * Now get commands one at a time and execute the
  288.      * appropriate routine to deal with them.
  289.      */
  290. #ifdef TIMERS
  291.     timer_init(timers, NTIMERS);
  292. #endif
  293.     for (;;) {
  294. #ifdef TIMERS
  295.         /* Don't try to read input unless there is some */
  296.         if (!timer_sleep(timers, NTIMERS))
  297.             continue;
  298. #endif
  299.         if (fgets(line, sizeof(line), stdin) == NULL)
  300.             break;
  301.         /* Strip trailing CR-LF */
  302.         cp = line + strlen(line) - 1;
  303.         while (cp >= line && (*cp == '\n' || *cp == '\r'))
  304.             *cp-- = '\0';
  305. #ifdef DEBUG
  306.         if (debug)
  307.             syslog(LOG_DEBUG, "<- \"%s\"", line);
  308. #endif
  309.  
  310.         /* Null command */
  311.         if ((argnum = parsit(line, &argp)) == 0)
  312.             continue;
  313.  
  314.         /* a motion to adjourn is always in order */
  315.         if (!strcasecmp(argp[0], "quit"))
  316.             break;
  317.  
  318.         for (i = 0; i < NUMCMDS; ++i)
  319.             if (!strcasecmp(cmdtbl[i].cmd_name, argp[0]))
  320.                 break;
  321.  
  322.         if (i < NUMCMDS) {
  323. #ifdef SETPROCTITLE
  324.             setproctitle("%s %s", hostname, argp[0]);
  325. #endif
  326. #ifdef AUTH
  327.             /* authentication required? */
  328.             if (cmdtbl[i].authreq == 1 && Needauth)
  329.                 {
  330. printf("%d Authentication required for command\r\n", ERR_NOAUTH);
  331.                 (void) fflush(stdout);
  332.                 continue;
  333.                 }
  334. #endif
  335.             (*cmdtbl[i].cmd_fctn)(argnum, argp);
  336.         } else {
  337. #ifdef SYSLOG
  338.             syslog(LOG_INFO, "%s unrecognized %s", hostname, line);
  339. #endif
  340.             printf("%d Command unrecognized.\r\n", ERR_COMMAND);
  341.             (void) fflush(stdout);
  342.         }
  343.     }
  344.  
  345.     printf("%d %s closing connection.  Goodbye.\r\n", OK_GOODBYE, host);
  346.  
  347.     (void) fflush(stdout);
  348.  
  349. #ifdef BATCHED_INPUT
  350.     batchcheck();
  351. #endif
  352.  
  353. #ifdef SYSLOG
  354.     if (ferror(stdout))
  355.         syslog(LOG_ERR, "%s disconnect: %m", hostname);
  356. #ifdef LOG
  357.     stats_finish();
  358. #endif
  359. #endif
  360.  
  361. #ifdef PROFILE
  362.     profile();
  363. #endif
  364.     exit(0);
  365. }
  366.  
  367. #ifdef TIMEOUT
  368. /*
  369.  * Called after TIMEOUT seconds of idle time to shut things down.
  370.  * XXX stats are not reported when this occurs
  371.  */
  372. static void
  373. timeout()
  374. {
  375.  
  376.     printf("%d Timeout after %d seconds, closing connection.\r\n",
  377.         ERR_FAULT, TIMEOUT);
  378. #ifdef SYSLOG
  379.     syslog(LOG_NOTICE, "%s timeout", hostname);
  380. #endif
  381.     (void) fflush(stdout);
  382. #ifdef BATCHED_INPUT
  383.     batchcheck();
  384. #endif
  385. #ifdef LOG
  386.     stats_finish();
  387. #endif
  388. #ifdef PROFILE
  389.     profile();
  390. #endif
  391.     exit(1);
  392. }
  393. #endif
  394.  
  395. #ifdef LOGINCHECK
  396. /*
  397.  * Called ever LOGINCHECK seconds to see if logins have been disabled.
  398.  * If so, shut down.
  399.  * XXX stats are not reported when this occurs
  400.  */
  401. static void
  402. logincheck()
  403. {
  404.     char host[MAXHOSTNAMELEN];
  405.  
  406.     if (access(NOLOGIN, F_OK) < 0)
  407.         return;
  408.     if (gethostname(host, sizeof(host)) < 0)
  409.         (void) strcpy(host, "Amnesiac");
  410.     printf("%d Logins are disabled on NNTP server %s. Try again later.\r\n",
  411.         ERR_ACCESS, host);
  412.     (void) fflush(stdout);
  413. #ifdef SYSLOG
  414.     syslog(LOG_INFO, "%s logins disabled%s",
  415.         hostname, firstlogincheck ? "" : " (kicked out)");
  416. #endif
  417. #ifdef BATCHED_INPUT
  418.     batchcheck();
  419. #endif
  420. #ifdef LOG
  421.     stats_finish();
  422. #endif
  423. #ifdef PROFILE
  424.     profile();
  425. #endif
  426.     exit(1);
  427. }
  428. #endif
  429.  
  430. #ifdef BATCHED_INPUT
  431. /*
  432.  * Called after BATCHCHECK seconds of idle time and at the end
  433.  * of a session to see if a batch needs to be launched.
  434.  */
  435. static void
  436. batchcheck()
  437. {
  438.     char errbuf[2 * NNTP_STRLEN];
  439.  
  440.     enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf);
  441. }
  442. #endif
  443.  
  444. /*
  445.  * Stats stuff
  446.  */
  447. static double        Tstart, Tfinish;
  448. static double        user, sys;
  449. #ifdef USG
  450. static time_t        start, finish;
  451. #else
  452. static struct timeval    start, finish;
  453. #endif
  454.  
  455. static char *
  456. stats_init()
  457. {
  458.     extern char    *ctime();
  459.  
  460. #ifdef USG
  461.     (void) time(&start);
  462.     Tstart = (double) start;
  463.     return(ctime(&start));
  464. #else
  465.     (void) gettimeofday(&start, (struct timezone *)NULL);
  466.     Tstart = (double) start.tv_sec + ((double)start.tv_usec)/1000000.0;
  467.     return(ctime(&start.tv_sec));
  468. #endif
  469. }
  470.  
  471. #ifdef LOG
  472. static void
  473. stats_finish()
  474. {
  475.     char        buf[NNTP_STRLEN];
  476. # ifdef USG
  477.     struct tms    cpu;
  478. # else
  479.     struct rusage    me, kids;
  480. # endif
  481.  
  482. #ifdef USG
  483.     (void) time(&finish);
  484.     Tfinish = (double) finish;
  485.  
  486. #ifndef HZ
  487. #define    HZ    60.0    /* typical system clock ticks - param.h */
  488. #endif
  489.  
  490.     (void) times(&cpu);
  491.     user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
  492.     sys  = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
  493. #else /* not USG */
  494.     (void) gettimeofday(&finish, (struct timezone *)NULL);
  495.     Tfinish = (double) finish.tv_sec + ((double)finish.tv_usec)/1000000.0;
  496.  
  497.     (void) getrusage(RUSAGE_SELF, &me);
  498.     (void) getrusage(RUSAGE_CHILDREN, &kids);
  499.  
  500.     user = (double) me.ru_utime.tv_sec + me.ru_utime.tv_usec/1000000.0 +
  501.         kids.ru_utime.tv_sec + kids.ru_utime.tv_usec/1000000.0;
  502.     sys = (double) me.ru_stime.tv_sec + me.ru_stime.tv_usec/1000000.0 +
  503.         kids.ru_stime.tv_sec + kids.ru_stime.tv_usec/1000000.0;
  504. #endif /* not USG */
  505.     if (grps_acsd)
  506.         syslog(LOG_INFO, "%s exit %d articles %d groups",
  507.             hostname, arts_acsd, grps_acsd);
  508.     if (nn_told)
  509.         syslog(LOG_INFO, "%s newnews_stats told %d took %d",
  510.             hostname, nn_told, nn_took);
  511.     if (ih_accepted || ih_rejected || ih_failed)
  512.         syslog(LOG_INFO,
  513.             "%s ihave_stats accepted %d rejected %d failed %d",
  514.             hostname,
  515.             ih_accepted,
  516.             ih_rejected,
  517.             ih_failed);
  518.     (void) sprintf(buf, "user %.3f system %.3f elapsed %.3f",
  519.         user, sys, Tfinish - Tstart);
  520.     syslog(LOG_INFO, "%s times %s", hostname, buf);
  521. }
  522. #endif /* LOG */
  523.  
  524. void
  525. doxmode(argc, argv)
  526.     int    argc;
  527.     char    *argv[];
  528. {
  529.     if (argc == 2 && !strcasecmp(argv[1], "reader"))
  530.         printf("%d OK.\r\n", canpost ? OK_CANPOST : OK_NOPOST);
  531.     else
  532.         printf("%d Syntax error\r\n", ERR_CMDSYN);
  533.     (void) fflush(stdout);
  534. }
  535.